﻿#pragma once
#include "Singleton.hpp"
#include "callback.h"
#include "code.h"
#include "config.h"
#include "hid_interface.h"
#include "protocol.h"
#include "threadpool.h"
#include <atomic>
#include <condition_variable>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <mutex>
#include <vector>

class hid_engine;

/**
 * HID解码器
 * @brief The hid_decoder class
 */
class hid_decoder {

private:
  std::mutex g_Mutex;
  std::mutex g_MutexArgs;
  condition_variable cv_;

  bool isRunning = true;
  bool decoding = false;
  int packageIndex = 0;
  int packageCount = 0;
  int totalPackageLength = 0;
  long contentLength = 0;
  bool randomFileDecoding = false;

  // 存放读取数据队列
  std::queue<std::vector<char>> buffer_queue_;

  /* 存储文本数据帧 */
  std::vector<char> buffer;

  /* 文件路径 */
  std::string downloadPath;

  /* 文件存放目录由外部传入 */
  std::string downloadDir;

  /* 文件句柄 */
  FILE *file = NULL;

  std::weak_ptr<OnHIDFrameListener> frameListenerPtr;
  std::weak_ptr<OnHIDErrorListener> errorListenerPtr;
  std::weak_ptr<OnHIDReadFileListener> readFileListenerPtr;
  std::weak_ptr<OnHIDReadRandomFileListener> randomFileListenerPtr;

  std::shared_ptr<hid_interface> hidInterface;
  std::unique_ptr<ThreadPool> threadPool;
  std::shared_ptr<config> cfg;

public:
  hid_decoder(std::shared_ptr<hid_interface> hitf,
              std::shared_ptr<config> _cfg);
  ~hid_decoder();

  /* 打开解码器 */
  void startDecoding();

  /* 关闭解码器 */
  void stopDecoding();

  // 生产线程
  void put(std::vector<char> &data);

  // 消费线程
  void take();

  /* 解码数据包 */
  int decode(const char *data, int size);

  /* 检查文件参数 */
  int checkFileArgs(const char *data, int size);

  /* 检查随机读写文件参数 */
  int checkRandomFileArgs(const char *data, int size);

  /* 检查文本数据包参数 */
  int checkFrameArgs(const char *data, int size);

  /* 解码文本数据包 */
  int decodeText(const char *data, int size);

  /* 解码文本数据包 */
  int decodeFile(const char *data, int size);

  /* 解码音频数据包 */
  int decodeAudioFrame(const char *data, int size);

  /* 解码视频数据包 */
  int decodeVideoFrame(const char *data, int size);

  /* 解码随机文件数据包 */
  int decodeRandomFile(const char *data, int size);

  /* 解码随机文件结束数据包 */
  int decodeRandomFileEnd(const char *data, int size);

  /* 解码随机文件暂停数据包 */
  int decodeRandomFilePause(const char *data, int size);

  /* 解码随机文件取消数据包 */
  int decodeRandomFileCancel(const char *data, int size);

  /* 下位机主动取消 */
  int decodeCancel(const char *data, int size);

  /* 解码ACK */
  int decodeACK(const char *data, int size);

  /* 检查命令是否匹配成功 */
  bool match(char head, char cmd);

  void release();

  std::string getDownloadFilePath() const;

  void setOnHIDErrorListener(std::weak_ptr<OnHIDErrorListener> l);
  void setOnHIDFrameListener(std::weak_ptr<OnHIDFrameListener> l);
  void setOnHIDReadFileListener(std::weak_ptr<OnHIDReadFileListener> l);
  void
  setOnHIDReadRandomFileListener(std::weak_ptr<OnHIDReadRandomFileListener> l);
};
